import paramiko  
import socketserver  
import threading  
import select  
import logging  # 导入日志模块

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class ForwardHandler(socketserver.BaseRequestHandler):  
    def handle(self):  
        try:  
            # 连接到 SSH 服务器的转发端口
            logging.info("正在尝试连接到 SSH 服务器的转发端口")
            channel = self.server.ssh_transport.open_channel(  
                "direct-tcpip",  
                (self.server.remote_host, self.server.remote_port),  
                self.request.getpeername()  
            )  
            # 等待 SSH 通道准备好
            if not channel.active:  
                logging.error("SSH 通道无法打开")
                raise Exception("SSH channel could not be opened")  
            logging.info("SSH 通道已成功打开")

            # 转发数据
            while True:  
                r, w, x = select.select([self.request, channel], [], [])  
                if self.request in r:  
                    data = self.request.recv(1024)  
                    if len(data) == 0:  
                        break  
                    channel.send(data)  
                    logging.info(f"从本地接收数据并发送到远程: {data}")
                if channel in r:  
                    data = channel.recv(1024)  
                    if len(data) == 0:  
                        break  
                    self.request.sendall(data)  
                    logging.info(f"从远程接收数据并发送到本地: {data}")
        finally:  
            channel.close()  
            logging.info("通道已关闭")

class ForwardingServer(socketserver.ThreadingMixIn, socketserver.TCPServer):  
    allow_reuse_address = True  

    def __init__(self, server_address, ssh_transport, remote_host, remote_port, handler_class=ForwardHandler):  
        self.ssh_transport = ssh_transport  
        self.remote_host = remote_host  
        self.remote_port = remote_port  
        # 将监听地址从 'localhost' 改为 '0.0.0.0'
        super().__init__(('0.0.0.0', server_address[1]), handler_class)  

def create_local_forward_tunnel(local_port, remote_host, remote_port, ssh_hostname, ssh_port, ssh_username, ssh_password):  
    ssh = paramiko.SSHClient()  
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())  
    ssh.connect(ssh_hostname, port=ssh_port, username=ssh_username, password=ssh_password)  
    logging.info("已成功连接到 SSH 服务器")

    # 创建转发服务器
    server = ForwardingServer(('0.0.0.0', local_port), ssh.get_transport(), remote_host, remote_port)  

    # 启动服务器线程
    server_thread = threading.Thread(target=server.serve_forever)  
    server_thread.daemon = True  
    server_thread.start()  
    logging.info(f"本地端口转发已启动，监听所有地址的端口：{local_port}，转发到远程主机：{remote_host}:{remote_port}")  

    # 保持主线程运行（例如，等待用户输入）
    try:  
        input("按回车退出...")  
    except KeyboardInterrupt:  
        logging.warning("用户中断操作")
        print("正在关闭本地端口转发...")  

    # 关闭 SSH 连接和转发服务器
    server.shutdown()  
    ssh.close()  
    logging.info("已关闭 SSH 连接和转发服务器")

# 使用示例  
SERVER = '192.168.236.144'  
SERVER_PORT = 22  
LOCAL_PORT = 10022  
REMOTE_HOST = '192.168.236.153'  # 假设您想要转发到远程服务器上的某个服务  
REMOTE_PORT = 80  # 假设是 HTTP 服务  
USERNAME = 'root'  
PASSWORD = 'root'  

create_local_forward_tunnel(LOCAL_PORT, REMOTE_HOST, REMOTE_PORT, SERVER, SERVER_PORT, USERNAME, PASSWORD)
